﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using Circa.Tools;

namespace Circa.Protocol.Irc {
    public class IrcProtocolProperties {
        public int NickNameLength { get; private set; }
        public int Channels { get; private set; }
        public int ChannelNameLength { get; private set; }
        public int TopicLength { get; private set; }
        public int KickMessageLength { get; private set; }
        public int AwayMessageLength { get; private set; }
        public int Targets { get; private set; }
        public int Modes { get; private set; }
        public int WatchListLength { get; private set; }
        public int SilenceListLength { get; private set; }

        public bool HasNamesX { get; private set; }
        public bool HasSafeList { get; private set; }
        public bool HasHcn { get; private set; }
        public bool HasWallChops { get; private set; }
        public bool HasBanExceptionList { get; private set; }
        public bool HasInviteList { get; private set; }

        private SafeDictionary<string,string> _tokens = new SafeDictionary<string,string>( );

        private SafeDictionary<char,int> _channelsByType = new SafeDictionary<char,int>( );
        private SafeDictionary<char,int> _channelListLengthByType = new SafeDictionary<char,int>( );

        private SafeDictionary<string,Action<int>> _integerTokenActions;
        private SafeDictionary<string,Action> _booleanTokenActions;

        public IrcProtocolProperties( ) {
            // IRC protocol defaults
            NickNameLength = 9;
            Channels = 10;
            ChannelNameLength = 32;
            TopicLength = 307;
            KickMessageLength = 307;
            AwayMessageLength = 307;
            Targets = 10;
            Modes = 3;
            WatchListLength = 0;
            SilenceListLength = 0;

            HasNamesX = false;
            HasSafeList = false;
            HasHcn = false;
            HasWallChops = false;
            HasBanExceptionList = false;
            HasInviteList = false;

            // token parsing
            _integerTokenActions = new SafeDictionary<string,Action<int>> {
                { "CHANNELLEN", (_) => ChannelNameLength = _ },
                { "NICKLEN",    (_) => NickNameLength    = _ },
                { "TOPICLEN",   (_) => TopicLength       = _ },
                { "KICKLEN",    (_) => KickMessageLength = _ },
                { "AWAYLEN",    (_) => AwayMessageLength = _ },
                { "MAXTARGETS", (_) => Targets           = _ },
                { "MODES",      (_) => Modes             = _ },
                { "WATCH",      (_) => WatchListLength   = _ },
                { "SILENCE",    (_) => SilenceListLength = _ },
            };

            _booleanTokenActions = new SafeDictionary<string,Action> {
                { "NAMESX",    ( ) => HasNamesX           = true },
                { "SAFELIST",  ( ) => HasSafeList         = true },
                { "HCN",       ( ) => HasHcn              = true },
                { "WALLCHOPS", ( ) => HasWallChops        = true },
                { "EXCEPTS",   ( ) => HasBanExceptionList = true },
                { "INVEX",     ( ) => HasInviteList       = true },
            };
        }

        public string this[ string key ] {
            get {
                return _tokens[ key ];
            }
        }

        public int GetChannelsByType( char type ) {
            return _channelsByType[ type ];
        }

        public int GetChannelListLengthByType( char type ) {
            return _channelListLengthByType[ type ];
        }

        /*
            TODO
            ==========================
            UHNAMES
            MAXCHANNELS=40
            CHANLIMIT=#:40
            MAXLIST=b:600,e:600,I:600
            WATCHOPTS=A
            CHANTYPES=#
            PREFIX=(qaohv)~&@%+
            CHANMODES=beI,kfL,lj,psmntirRcOAQKVCuzNSMTG
            NETWORK=Foonetic
            CASEMAPPING=ascii
            EXTBAN=~,cqnr
            ELIST=MNUCT
            STATUSMSG=~&@%+
            CMDS=KNOCK,MAP,DCCALLOW,USERIP
        */
        public void SetFromISupportTokens( IList<string> tokens ) {
            foreach ( string token in tokens ) {
                // a token with a space is, most likely, the last token on the line, which (usually!) says something like "is supported by this
                // server". however, the wording cannot be relied on, and regular RPL_ISUPPORT tokens do not contain spaces, so this heuristic
                // _ought_ to be reliable.
                if ( token.Contains( ' ' ) ) {
                    return;
                }

                string key, value;
                int index = token.IndexOf( '=' );

                if ( index > -1 ) {
                    value = token.Substring( index + 1 );
                    key = token.Substring( 0, index );
                } else {
                    value = null;
                    key = token;
                }
                _tokens.Add( key, value );

                if ( null == value ) {
                    if ( null != _booleanTokenActions[ key ] ) {
                        _booleanTokenActions[ key ]( );
                        return;
                    }
                } else {
                    Action<int> integerAction = _integerTokenActions[ key ];
                    int param = 0;

                    if ( null != integerAction ) {
                        try {
                            param = Int32.Parse( value, NumberStyles.Integer );
                        }
                        catch ( FormatException e ) {
                            Debug.Print( "IrcProtocolProperties.SetFromISupportToken: FormatException trying to parse NICKLEN='{0}': {1}", value, e.ToString( ) );
                            return;
                        }
                        catch ( OverflowException e ) {
                            Debug.Print( "IrcProtocolProperties.SetFromISupportToken: OverflowException trying to parse NICKLEN='{0}': {1}", value, e.ToString( ) );
                            return;
                        }
                        integerAction( param );
                        return;
                    }
                }

                Debug.Print( "IrcProtocolProperties.SetFromISupportToken: unknown RPL_ISUPPORT token '{0}'", token );
            }
        }

    }

}
